# coding: utf-8
# json モジュールを使ってみる

# json モジュールをインポート
import json, struct, re, codecs

# ================================================================
# info
# ================================================================
# オプション
OPTION = json.load( open("option.conf") )
# 構造
STRUCT = json.load( open( OPTION["struct"] ) )

# パラメータ
f = codecs.open( OPTION["param"], "r", "utf-8" )
param_str = f.read()
f.close()
param_str = re.sub("//.*", "", param_str)
param_str = re.sub("/\*.*\*/", "", param_str)

PARAM = json.loads( param_str )
#PARAM = json.loads( open( OPTION["param"] ) )

# エンディアン
ENDIAN_PREFIX = "<"
if OPTION["endian"] == "big": ENDIAN_PREFIX = ">"

# ================================================================
# 調整
# ================================================================
def seriesElement(element):
    data_list = []
    
    def _seriesElement(data):
        data_list.append(data)
        if "child" in data:
            for child in data["child"]: _seriesElement(child)
    
    _seriesElement(element)
    
    return data_list
    
# ================================================================
# 調整
# ================================================================
def ajastJsonData(json_data):
    # データをリスト化
    data_list = seriesElement(json_data)
    
    # デフォルト値をセット
    def _setDefaultValue(value, param, key=None):
        type = param["type"]
        
        if key == None:
            for key in param["child"]:
                _setDefaultValue(value, PARAM[key], key)
                
        elif key not in value:
            if type == "string": value[key] = param["value"]
            elif type == "number": value[key] = param["value"]
            elif type == "bool": value[key] = param["value"]
            elif type == "group":
                value[key] = {}
        
        if type == "group":
            for subkey in param["child"]:
                _setDefaultValue(value[key], PARAM[subkey], subkey)
    
    for value in data_list:
        # タイプ
        type = value["base-prop"]["type"]
        _setDefaultValue( value, PARAM[type] )
    
    for i, value in enumerate(data_list): value["base-prop"]["id"] = i
    

# ================================================================
# convert
# ================================================================
def jsonToData(json_data):
    # データ
    data = {}
    data["value"] = []
    data["format"] = []
    data["child"] = []
    
    # タイプ
    type = json_data["base-prop"]["type"]
    
    # 処理
    def _jsonToData(value, param):
#        print(param)
        type = param["type"]
        
        if type == "string":
#            data["value"].append( value )
            data["value"].append( value.encode() )
            data["format"].append(param["format"])
        
        elif type == "number":
            if param["format"] in ["I", "i"]:
                data["value"].append(int(value))
            else:
                data["value"].append(value)
                
            data["format"].append(param["format"])
        
        elif type == "bool":
            data["value"].append(value)
            data["format"].append(param["format"])
            
        elif type == "group":
            for key in param["child"]:
                _jsonToData(value[key], PARAM[key])
    
    # json を データ化
    _jsonToData(json_data, PARAM[type])
    
    # 子供もデータ化
    if "child" in json_data:
        for child in json_data["child"]:
            data["child"].append( jsonToData(child) )
    
#    print("data  : ", data["value"])
#    print("format: ", data["format"])
    return data

# ================================================================
# convert
# ================================================================
def convert(json_data):
    # 調整
    ajastJsonData( json_data["element"] )
    # データ化
    data = jsonToData( json_data["element"] )
    
#    print(json.dumps(data, sort_keys=True, indent=4))
    
    binary_data = []
    
    def _convert(data):
        print(data["value"])
        print(data["format"])
        f = " ".join(data["format"])    # フォーマット
        s = struct.Struct(ENDIAN_PREFIX + f)            # 構造体
        v = data["value"]               # データ
        b = s.pack( *v )                # パック
        
        # 確認
        print(b)
        print(s.unpack(b))
        
        # 追加
        binary_data.append(b)
        
        # 子供もバイナリ化
        for child in data["child"]: _convert(child)
        
    _convert(data)
    
    return b''.join(binary_data)

# ================================================================
# main時のtest
# ================================================================
def main():
    # コンバート
    result = convert(json.load( open( OPTION["input"] ) ))
    
    f = open(OPTION["output"], "wb")
    f.write( result )
    f.close()

# メイン時
if __name__ == '__main__':
    print("[START]")
    main()
    print("[FINISH]")

